<i18n locale="en" lang="yaml">
retryMinutes: 'Please retry after {n} minute | Please retry after {n} minutes'
</i18n>

<i18n locale="zh-CN" lang="yaml">
Please select sign in method: 请选择登录方式
System built-in user        : 系统内置用户
Username                    : 请输入账号
Password                    : 请输入密码
Captcha                     : 请输入验证码
Sign In                     : 登录

Please input username             : 请输入用户名
Please input password             : 请输入密码
Please input captcha              : 请输入验证码
Captcha should be a 4-digit number: 验证码为 4 位数字

Invalid username or password                                                                 : 用户名或密码错误
Invalid captcha                                                                              : 验证码错误或无效
User has been disabled                                                                       : 当前用户已被禁用
Too many bad passwords, please try again later                                               : 密码输入错误次数过多，请稍后再试
retryMinutes                                                                                 : 请在 {n} 分钟后重试
Worker no response, please check the status of this system                                   : 工作单元没有响应，请检查系统状态
Integration sign-in func returned an unexpected value, please contact admin                  : 集成登录函数返回了未预期的结果，请联系系统管理员
Sign in failed. Error occured in integration sign-in func, please concat admin               : 登录失败。集成登录函数抛出异常，请联系系统管理员
Sign in failed. Integration sign-in func timeout, please concat admin                        : 登录失败，集成登录函数超时，请联系系统管理员
Sign in failed. Integration sign-in func returned `False` or empty value, please concat admin: 登录失败，集成登录函数返回`False`或空内容，请联系系统管理员
</i18n>

<!-- Generated by OpenCC START -->
<i18n locale="zh-HK" lang="yaml">
Captcha: 請輸入驗證碼
Captcha should be a 4-digit number: 驗證碼為 4 位數字
Integration sign-in func returned an unexpected value, please contact admin: 集成登錄函數返回了未預期的結果，請聯繫系統管理員
Invalid captcha: 驗證碼錯誤或無效
Invalid username or password: 用户名或密碼錯誤
Password: 請輸入密碼
Please input captcha: 請輸入驗證碼
Please input password: 請輸入密碼
Please input username: 請輸入用户名
Please select sign in method: 請選擇登錄方式
Sign In: 登錄
Sign in failed. Error occured in integration sign-in func, please concat admin: 登錄失敗。集成登錄函數拋出異常，請聯繫系統管理員
Sign in failed. Integration sign-in func returned `False` or empty value, please concat admin: 登錄失敗，集成登錄函數返回`False`或空內容，請聯繫系統管理員
Sign in failed. Integration sign-in func timeout, please concat admin: 登錄失敗，集成登錄函數超時，請聯繫系統管理員
System built-in user: 系統內置用户
Too many bad passwords, please try again later: 密碼輸入錯誤次數過多，請稍後再試
User has been disabled: 當前用户已被禁用
Username: 請輸入賬號
Worker no response, please check the status of this system: 工作單元沒有響應，請檢查系統狀態
retryMinutes: 請在 {n} 分鐘後重試
</i18n>
<i18n locale="zh-TW" lang="yaml">
Captcha: 請輸入驗證碼
Captcha should be a 4-digit number: 驗證碼為 4 位數字
Integration sign-in func returned an unexpected value, please contact admin: 整合登入函式返回了未預期的結果，請聯絡系統管理員
Invalid captcha: 驗證碼錯誤或無效
Invalid username or password: 使用者名稱或密碼錯誤
Password: 請輸入密碼
Please input captcha: 請輸入驗證碼
Please input password: 請輸入密碼
Please input username: 請輸入使用者名稱
Please select sign in method: 請選擇登入方式
Sign In: 登入
Sign in failed. Error occured in integration sign-in func, please concat admin: 登入失敗。整合登入函式丟擲異常，請聯絡系統管理員
Sign in failed. Integration sign-in func returned `False` or empty value, please concat admin: 登入失敗，整合登入函式返回`False`或空內容，請聯絡系統管理員
Sign in failed. Integration sign-in func timeout, please concat admin: 登入失敗，整合登入函式超時，請聯絡系統管理員
System built-in user: 系統內建使用者
Too many bad passwords, please try again later: 密碼輸入錯誤次數過多，請稍後再試
User has been disabled: 當前使用者已被禁用
Username: 請輸入賬號
Worker no response, please check the status of this system: 工作單元沒有響應，請檢查系統狀態
retryMinutes: 請在 {n} 分鐘後重試
</i18n>
<!-- Generated by OpenCC END -->

<template>
  <div class="sign-in">
    <div class="sign-in-area">
      <div class="sign-in-panel">
        <el-form ref="form" :model="form" :rules="formRules" class="sign-in-form">
          <Logo type="auto" class="logo" height="70px"></Logo>

          <el-form-item prop="funcId" v-if="signInFuncs && signInFuncs.length > 0">
            <el-select v-model="form.funcId" :placeholder="$t('Please select sign in method')">
              <i slot="prefix" class="fth-man-icon fth-man-icon-integration"></i>
              <el-option :label="$t('System built-in user')" :value="BUILTIN_SIGN_IN_FUNC_ID"></el-option>
              <el-option v-for="opt in signInFuncs" :label="opt.title" :key="opt.id" :value="opt.id"></el-option>
            </el-select>
          </el-form-item>

          <el-form-item prop="username">
            <el-input tabindex="1"
              maxlength="60"
              :placeholder="$t('Username')"
              v-model="form.username">
              <i slot="prefix" class="fth-man-icon fth-man-icon-account-number"></i>
            </el-input>
          </el-form-item>

          <el-form-item prop="password" :error="respError.password">
            <el-input tabindex="2"
              maxlength="100"
              show-password
              :placeholder="$t('Password')"
              v-model="form.password">
              <i slot="prefix" class="fth-man-icon fth-man-icon-password"></i>
            </el-input>
          </el-form-item>

          <el-form-item _captcha prop="captcha" :error="respError.captcha">
            <el-input tabindex="3"
              :maxlength="4"
              :clearable="true"
              @keyup.enter.native="submitData"
              @focus="autoFillCaptcha"
              :placeholder="$t('Captcha')"
              v-model="form.captcha">
              <i slot="prefix" class="fth-man-icon fth-man-icon-verification-code"></i>
            </el-input>
            <CaptchaImage
              captcha-category='signIn'
              :captcha-token="form.captchaToken"
              @click.native="refreshCaptcha()" />
          </el-form-item>

          <el-form-item>
            <el-button tabindex="4" type="primary" @click="submitData" :disabled="isSigningIn">
              <i v-if="isSigningIn" class="fa fa-fw fa-circle-o-notch fa-spin"></i>
              {{ $t('Sign In')}}
            </el-button>

            <div class="ui-extra">
              <el-dropdown class="ui-locale-select" @command="$root.setUILocale">
                <span><i class="fa fa-fw fa-globe"></i> {{ uiLocaleDetail.name }}</span>
                <el-dropdown-menu slot="dropdown">
                  <el-dropdown-item v-for="_locale in C.UI_LOCALE" :key="_locale.key" :command="_locale.key">
                    <span :class="{ 'selected-option': uiLocaleDetail.key === _locale.key }">
                      {{ _locale.name }}
                      <span class="ui-locale-tip" v-if="_locale.tip">{{ _locale.tip }}</span>
                    </span>
                  </el-dropdown-item>
                </el-dropdown-menu>
              </el-dropdown>

              <div class="ui-error-message text-bad" v-if="respError.other">
                {{ respError.other }}
                <small class="text-bad" v-if="respError.otherSub">
                  <br>{{ respError.otherSub }}
                </small>
              </div>
            </div>
          </el-form-item>
        </el-form>
      </div>
      <p class="text-main version-info">{{ $t('Version') }}{{ $t(':') }}{{ FULL_VERSION }}</p>
    </div>
  </div>
</template>

<script>
import CaptchaImage from '@/components/CaptchaImage'

export default {
  name: 'Index',
  components: {
    CaptchaImage,
  },
  watch: {
  },
  methods: {
    async submitData() {
      this.isSigningIn = true;
      this.submitFailed = false;

      let prevFormFuncId   = this.form.funcId;
      let prevFormUsername = this.form.username;

      try {
        await this.$refs.form.validate();
      } catch(err) {
        this.isSigningIn = false;
        return console.error(err);
      }

      await this.$refs.form.clearValidate();
      this.T.jsonClear(this.respError);

      let _formData = this.T.jsonCopy(this.form);

      let signInURL = null;
      let signInBody = {
        captchaToken: _formData.captchaToken,
        captcha     : _formData.captcha,
        signIn: {
          username: _formData.username,
          password: _formData.password,
        }
      };

      if (this.isBuiltInSignIn) {
        signInURL = '/api/v1/auth/do/sign-in';

      } else {
        signInURL = '/api/v1/func/integration/sign-in';
        signInBody.signIn.funcId = _formData.funcId;
      }

      let apiRes = await this.T.callAPI('post', signInURL, {
        body    : signInBody,
        feedback: { muteError: true }, // Sign-in failures are displayed directly on the page instead of a pop-up box.
      });

      this.$refs.form.resetFields();

      this.form.funcId   = prevFormFuncId;
      this.form.username = prevFormUsername;

      if (!apiRes.ok) {
        this.refreshCaptcha();

        switch(apiRes.reason) {
          /* Built-in sign in failure */
          case 'EUserPassword':
            this.respError.password = this.$t('Invalid username or password');
            break;

          case 'EUserCaptcha':
            this.respError.captcha = this.$t('Invalid captcha');
            break;

          case 'EUserDisabled':
            this.respError.other = this.$t('User has been disabled');
            break;

          case 'EUserLocked':
            this.respError.other = this.$t('Too many bad passwords, please try again later');
            break;

          /* Integrated sign in failure */
          case 'EWorkerNoResponse':
            this.respError.other = this.$t('Worker no response, please check the status of this system');
            break;

          case 'EFuncResultParsingFailed':
            this.respError.other = this.$t('Integration sign-in func returned an unexpected value, please contact admin');
            break;

          case 'EFuncFailed.SignInFuncRaisedException':
            this.respError.other = apiRes.message || this.$t('Sign in failed. Error occured in integration sign-in func, please concat admin');
            break;

          case 'EFuncFailed.SignInFuncTimeout':
            this.respError.other = this.$t('Sign in failed. Integration sign-in func timeout, please concat admin');
            break;

          case 'EFuncFailed.SignInFuncReturnedFalseOrNothing':
            this.respError.other = this.$t('Sign in failed. Integration sign-in func returned `False` or empty value, please concat admin');
            break;
        }

        switch(apiRes.reason) {
          /* User locked */
          case 'EUserPassword':
          case 'EUserLocked':
            if (apiRes.detail && apiRes.detail.signInWaitTimeout) {
              this.respError.other    = this.$t('Too many bad passwords, please try again later');
              this.respError.otherSub = this.$tc('retryMinutes', Math.ceil(apiRes.detail.signInWaitTimeout / 60));
            }
            break;
        }

        this.isSigningIn = false;
        this.submitFailed = true;
        return;
      }

      let xAuthToken = apiRes.data.xAuthToken;
      this.$store.dispatch('signIn', xAuthToken);

      setTimeout(() => {
        this.isSigningIn = false;
      }, 1000);
    },
    refreshCaptcha() {
      this.form.captchaToken = Math.random().toString();
      this.form.captcha = '';
    },
    autoFillCaptcha() {
      if (this.$store.getters.SYSTEM_INFO('MODE') === 'prod') return;
      if (!this.form.username || !this.form.password) return;

      let captchaToFill = this.form.captchaToken.slice(-4);
      this.form.captcha = '';
      let T = setInterval(() => {
        this.form.captcha = captchaToFill.slice(0, this.form.captcha.length + 1);
        if (this.form.captcha.length === 4) {
          clearInterval(T);
          setTimeout(() => {
            this.submitData();
          }, 500);
        }
      }, 100);
    },
  },
  computed: {
    FULL_VERSION() {
      if (this.$store.getters.SYSTEM_INFO('EDITION')) {
        return `${this.$store.getters.SYSTEM_INFO('VERSION')} (${this.$store.getters.SYSTEM_INFO('EDITION')})`;
      } else {
        return this.$store.getters.SYSTEM_INFO('VERSION');
      }
    },
    BUILTIN_SIGN_IN_FUNC_ID() {
      return 'builtIn';
    },
    signInFuncs() {
      return this.$store.getters.SYSTEM_INFO('INTEGRATED_SIGN_IN_FUNC');
    },
    isBuiltInSignIn() {
      return this.T.isNothing(this.signInFuncs) || this.form.funcId === this.BUILTIN_SIGN_IN_FUNC_ID;
    },
    uiLocaleDetail() {
      return this.C.UI_LOCALE_MAP.get(this.$store.getters.uiLocale);
    },
  },
  props: {
  },
  data() {
    return {
      isSigningIn: false,

      respError: {
        password: null,
        captcha : null,
        other   : null,
        otherSub: null,
      },
      form: {
        captchaToken: null,
        captcha     : null,
        funcId      : null,
        username    : null,
        password    : null,
      },
      formRules: {
        username: [
          {
            trigger : 'change',
            message : this.$t('Please input username'),
            required: true,
          },
        ],
        password: [
          {
            trigger : 'change',
            message : this.$t('Please input password'),
            required: true,
          },
        ],
        captcha: [
          {
            trigger : 'change',
            message : this.$t('Please input captcha'),
            required: true,
          },
          {
            trigger : 'change',
            message : this.$t('Captcha should be a 4-digit number'),
            length  : 4,
            pattern : /^\d{4}$/g
          },
        ],
      },

      submitFailed: false,
    }
  },
  created() {
    // Use built-in sign in method for default
    this.form.funcId = this.BUILTIN_SIGN_IN_FUNC_ID;

    // Refresh the captcha box when entering the page
    this.refreshCaptcha();
  },
}
</script>

<style scoped>
.logo {
  display: block;
  margin: 10px auto 25px auto;
}
.sign-in {
  background-color: var(--base-light);
  height: 100%;
  width: 100%;
  z-index: 9999;
}
.sign-in-area {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
}
.sign-in-panel {
  width: 554px;
  background-color: var(--base);
  position: relative;
  border-radius: 10px;
  box-shadow: var(--dialog-shadow);
}
.sign-in-panel .ui-extra {
  display: flex;
  align-items: center;
  flex-direction: row-reverse;
  justify-content: space-between;
}
.sign-in-panel .ui-error-message {
  word-break: break-word;
  font-size: 14px;
  line-height: 1.5;
}
.sign-in-panel .ui-locale-select {
  padding-top: 20px;
  font-size: 16px;
  color: var(--primary);
  cursor: pointer;
  white-space: nowrap;
}

.sign-in-form {
  padding: 5px 50px 5px 50px;
}
.sign-in-title {
  font-size: 20px;
  color: #222;
  margin-bottom: 18px;
}
.fth-man-icon {
  font-family: fth-man-icons !important;
  speak: none;
  font-size: 18px;
  font-style: normal;
  font-weight: 700;
  font-variant: normal;
  text-transform: none;
  color: var(--text-xlight);
  position: relative;
  top: 3px;
}
.fth-man-icon-integration:before {
  content: "\E902";
}
.fth-man-icon-account-number:before {
  content: "\E900";
}
.fth-man-icon-password:before {
  content: "\E909";
}
.fth-man-icon-verification-code:before {
  content: "\E90E";
}

.version-info {
  text-align: center;
  margin-top: 5px;
  margin-right: 15px;
  font-size: 12px;
}
</style>
<style>
.ui-locale-tip {
  margin-left: 5px;
  padding: 4px;
  border-radius: 3px;
  background: var(--primary);
  display: inline-block;
  font-size: 12px;
  color: white !important;
  font-weight: normal !important;
  line-height: 1;
}

.sign-in-form input {
  height: 47px;
  font-size: 16px;
}
.sign-in-form button {
  height: 46px;
  width: 100%;
  font-size: 16px;
}
.sign-in-form .el-input__inner {
  padding-left: 46px;
}
.sign-in-form .el-input__prefix {
  left: 13px;
  top: 2px;
  font-size: 16px;
}
.sign-in-form [_captcha] .el-input {
  width: 300px;
}
.sign-in-form [_captcha] .captcha-image {
  height: 45px;
  width: 136px;
  overflow: hidden;
}
</style>
